# 驱动层TX MGMT处理过程 管理帧主要包含Beacon、Probe、Authentication、Association,其中Beacon是预先分配好内存,并填充内容,当FW上报beacon发送事件的时候,会调用ol_beacon_swba_handler函数,会把beacon帧发送发送到htc层。 其他的管理帧,则是在用到的时候现场分配内存,统一调用ieee80211_send_mgmt函数发送到htc层,下面以auth为例,说明了大致过程: ``` ieee80211_send_auth ieee80211_send_mgmt wlan_mgmt_txrx_mgmt_frame_tx{ tx_ops->mgmt_txrx_tx_ops.mgmt_tx_send(vdev, buf, desc->desc_id, mgmt_tx_params) 实际调用 ol_if_mgmt_send 因为 tx_ops->mgmt_txrx_tx_ops.mgmt_tx_send = ol_if_mgmt_send { ol_ath_tx_mgmt_wmi_send(ic, nbuf, ni, mgmt_tx_params); ol_mgmt_send wmi_mgmt_unified_cmd_send wmi_handle->ops->send_mgmt_cmd 实际调用 send_mgmt_cmd_tlv,因为 wmi_handle->ops->send_mgmt_cmd = send_mgmt_cmd_tlv { wmi_unified_cmd_send wmi_htc_send_pkt htc_send_pkt __htc_send_pkt } } } ``` ## Beacon 1. 初始化缓存,并设置beacon的内容到av_wbuf中 ``` ol_ath_vap_create_post_init(struct vdev_mlme_obj *vdev_mlme, int flags) { vap->iv_hostap_up_pre_init = ol_ath_hostap_up_pre_init; } QDF_STATUS mlme_ext_vap_up_pre_init(struct wlan_objmgr_vdev *vdev, bool restart) { switch (opmode) { case IEEE80211_M_STA: ic->ic_vap_set_param(vap, IEEE80211_VHT_SUBFEE, 0); reassoc = restart; ic->ic_newassoc(ni, !reassoc); break; case IEEE80211_M_HOSTAP: case IEEE80211_M_IBSS: status = vap->iv_hostap_up_pre_init(vdev, restart); break; default: break; } } ol_ath_hostap_up_pre_init ol_ath_beacon_alloc ol_ath_vap_iter_beacon_alloc // 填充内容 avn->av_wbuf = ieee80211_beacon_alloc(ni, &avn->av_beacon_offsets); ``` 2. 注册beacon事件到fw ``` void ol_ath_beacon_soc_attach(ol_ath_soc_softc_t *soc) { struct wmi_unified *wmi_handle; wmi_handle = lmac_get_wmi_hdl(soc->psoc_obj); /* Register WMI event handlers */ //注册ol_beacon_swba_handler地方 wmi_unified_register_event_handler((void *)wmi_handle, wmi_host_swba_event_id,ol_beacon_swba_handler, WMI_RX_UMAC_CTX); } 实际调用ol_beacon_swba_handler地方 参见文档《接收管理帧过程》中关于wmi_unified_register_event_handler 实际上就是在__wmi_control_rx中调用 ``` 3. 如果fw发送beacon 的事件,则开始发送beacon ``` ol_beacon_swba_handler ol_ath_beacon_swba_handler ol_prepare_send_vap_bcn wlan_mgmt_txrx_beacon_frame_tx { tx_ops->mgmt_txrx_tx_ops.beacon_send(vdev, buf) 实际调用ol_ath_mgmt_beacon_send ,因为 tx_ops->mgmt_txrx_tx_ops.beacon_send = ol_ath_mgmt_beacon_send { ol_ath_beacon_send wmi_unified_beacon_send_cmd wmi_handle->ops->send_beacon_send_cmd 实际调用 send_beacon_send_cmd_tlv 因为 wmi_handle->ops->send_beacon_send_cmd = send_beacon_send_cmd_tlv { wmi_unified_cmd_send 再往下就和 管理帧一样的 wmi_htc_send_pkt htc_send_pkt __htc_send_pkt } } } ``` ## Probe ### 探测请求 Probe Request ``` mlme_vdev_subst_start_conn_progress_event mlme_vdev_start_continue_cb { { wlan_assoc_sm_start(wlan_mlme_get_assoc_sm_handle(vap->vdev_obj),mlme_cm_get_active_scan_entry(vap),req.prev_bssid.bytes); ieee80211_mlme_join_infra_continue(vap,EOK); // 这里发送probe 请求帧 // WIM_LOG_DEBUG("SMAC:%s DMAC:%s",ether_sprintf(vap->iv_myaddr),ether_sprintf(ni->ni_bssid)); } } ieee80211_mlme_join_infra_continue { if ((ic->ic_strict_pscan_enable && IEEE80211_IS_CHAN_PASSIVE(ic->ic_curchan)) && !vap->iv_wps_mode) { mlme_priv->im_request_type = MLME_REQ_NONE; IEEE80211_DELIVER_EVENT_MLME_JOIN_COMPLETE_INFRA(vap, IEEE80211_STATUS_SUCCESS); return; } else { /* Send a direct probe to increase the odds of receiving a probe response */ // 这里调用,这里是否可以取消该probe req 参见本章《高阶》中介绍 ieee80211_send_probereq(ni, vap->iv_myaddr, ni->ni_bssid,ni->ni_bssid, ni->ni_essid, ni->ni_esslen, vap->iv_opt_ie.ie, vap->iv_opt_ie.length); //WIM_LOG_DEBUG("SMAC:%s DMAC:%s",ether_sprintf(vap->iv_myaddr),ether_sprintf(ni->ni_bssid)); } } ieee80211_send_probereq ieee80211_send_mgmt ``` ```c int ieee80211_send_probereq(struct ieee80211_node *ni, const u_int8_t *sa, const u_int8_t *da, const u_int8_t *bssid, const u_int8_t *ssid, const u_int32_t ssidlen, const void *optie, const size_t optielen); { wbuf_t wbuf; enum ieee80211_phymode mode; struct ieee80211_frame *wh; // 分配空间 wbuf = wbuf_alloc(ic->ic_osdev, WBUF_TX_MGMT, MAX_TX_RX_PACKET_SIZE); // 把内存转换为802.11头指针wh wh = (struct ieee80211_frame *)wbuf_header(wbuf); // 取frm 然后设置里面的内容 frm = (u_int8_t *)&wh[1]; /* * prreq frame format *[tlv] ssid *[tlv] supported rates *[tlv] extended supported rates *[tlv] HT Capabilities *[tlv] VHT Capabilities *[tlv] user-specified ie's */ frm = ieee80211_add_ssid(frm, ssid, ssidlen); mode = ieee80211_get_current_phymode(ic); /* XXX: supported rates or operational rates? */ frm = ieee80211_add_rates(frm, &vap->iv_op_rates[mode]); frm = ieee80211_add_xrates(vap, frm, &vap->iv_op_rates[mode]); // 增加ie 域 frm = ieee80211_mlme_app_ie_append(vap, IEEE80211_FRAME_TYPE_PROBEREQ, frm); #if QCN_IE frm = ieee80211_add_qcn_info_ie(frm, vap, &ie_len, QCN_MAC_PHY_PARAM_IE_TYPE, NULL); #endif frm = ieee80211_add_generic_vendor_capabilities_ie(frm, ic); // 发送帧 return ieee80211_send_mgmt(vap,ni, wbuf,true); } ``` ### 探测请求应答 Probe Response ``` ieee80211_send_proberesp ieee80211_send_mgmt ``` ```c int ieee80211_send_proberesp(struct ieee80211_node *ni, u_int8_t *macaddr, const void *optie, const size_t optielen, struct ieee80211_framing_extractx *extractx) { // 申请内存空间 wbuf = wbuf_alloc(ic->ic_osdev, WBUF_TX_MGMT, MAX_TX_RX_PACKET_SIZE); // 把内存转换为802.11头指针wh wh = (struct ieee80211_frame *)wbuf_header(wbuf); ieee80211_send_setup(vap, ni, wh, IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP, vap->iv_myaddr, macaddr, ieee80211_node_get_bssid(ni)); // 取frm 然后设置里面的内容 frm = (u_int8_t *)&wh[1]; //此处省略设置过程 // 发送地方 ieee80211_send_mgmt(vap,ni, wbuf,true); } ``` ## Authentication ### 身份认证 Authentication ``` ieee80211_send_auth ieee80211_send_mgmt ``` ```c int ieee80211_send_auth( struct ieee80211_node *ni, u_int16_t seq, u_int16_t status, u_int8_t *challenge_txt, u_int8_t challenge_len, struct ieee80211_app_ie_t* optie ) { wbuf = wbuf_alloc(ic->ic_osdev, WBUF_TX_MGMT, MAX_TX_RX_PACKET_SIZE); wh = (struct ieee80211_frame *)wbuf_header(wbuf); frm = (u_int8_t *)&wh[1]; // 设置frm // 实际发送的地方 ieee80211_send_mgmt(vap,ni, wbuf,false) } ``` ### 去身份认证 Deauthentication ``` ieee80211_send_deauth ieee80211_send_mgmt ``` ```c int ieee80211_send_deauth(struct ieee80211_node *ni, u_int16_t reason) { wbuf = wbuf_alloc(ic->ic_osdev, WBUF_TX_MGMT, (sizeof(struct ieee80211_frame)+frlen)); wh = (struct ieee80211_frame *)wbuf_header(wbuf); frm = (u_int8_t *)&wh[1]; if (vap->iv_vap_is_down) return ieee80211_send_mgmt(vap, ni, wbuf, true); else return ieee80211_send_mgmt(vap, ni, wbuf, false); } ``` ## Association ### 关联请求 Association or Reassociation Request ``` ieee80211_send_assoc ieee80211_send_mgmt ``` ```c int ieee80211_send_assoc(struct ieee80211_node *ni, int reassoc, u_int8_t *prev_bssid) { // 申请空间 wbuf = wbuf_alloc(ic->ic_osdev, WBUF_TX_MGMT, MAX_TX_RX_PACKET_SIZE); // 设置内容 length = ieee80211_setup_assoc(ni, (struct ieee80211_frame *)wbuf_header(wbuf), reassoc, prev_bssid); // 传输到os层 /* Callback to allow OS layer to copy assoc/reassoc frame (Vista requirement) */ IEEE80211_DELIVER_EVENT_MLME_ASSOC_REQ(vap, wbuf); // 发送 return ieee80211_send_mgmt(vap,ni,wbuf,false); } ``` ### 关联请求应答 Association Response ``` ieee80211_send_assocresp ieee80211_send_mgmt ``` ```c int ieee80211_send_assocresp(struct ieee80211_node *ni, u_int8_t reassoc, u_int16_t reason, struct ieee80211_app_ie_t* optie) { //申请并设置wbuf内容 wbuf = ieee80211_setup_assocresp(ni, NULL, reassoc, reason, optie); // 发送 ieee80211_send_mgmt(vap,ni, wbuf,false); } ``` ### 去关联 Disassociation ``` ieee80211_send_disassoc ieee80211_send_disassoc_with_callback(ni, reason, NULL, NULL); ieee80211_send_mgmt ``` ```c int ieee80211_send_disassoc(struct ieee80211_node *ni, u_int16_t reason) { int retval; retval = ieee80211_send_disassoc_with_callback(ni, reason, NULL, NULL); { wbuf = wbuf_alloc(ic->ic_osdev, WBUF_TX_MGMT, MAX_TX_RX_PACKET_SIZE); wh = (struct ieee80211_frame *)wbuf_header(wbuf); ieee80211_flush_peer_mgmt_queue(ni); // 实际发送地方 if (vap->iv_vap_is_down) return ieee80211_send_mgmt(vap, ni, wbuf, true); else return ieee80211_send_mgmt(vap, ni, wbuf, false); frm = (u_int8_t *)&wh[1]; } return retval; } ``` ## ieee80211_send_mgmt 通用函数 ```c int ieee80211_send_mgmt(struct ieee80211vap *vap,struct ieee80211_node *ni, wbuf_t wbuf, bool force_send) { u_int8_t subtype; u_int8_t fc_type; int retval; struct ieee80211_frame *wh; ni = ieee80211_try_ref_node(ni, WLAN_MGMT_TX_ID); if (!ni) { wbuf_complete(wbuf); return EOK; } else { wlan_wbuf_set_peer_node(wbuf, ni); } wh = (struct ieee80211_frame *)wbuf_header(wbuf); fc_type = wh->i_fc[0]; /* * if forced sleep is set then turn on the powersave * bit on all management except for the probe request. */ if (ieee80211_vap_forced_sleep_is_set(vap)) { subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; if (subtype != IEEE80211_FC0_SUBTYPE_PROBE_REQ) { wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; wbuf_set_pwrsaveframe(wbuf); } } /* * call registered function to add any additional IEs. */ if (vap->iv_output_mgmt_filter) { if (vap->iv_output_mgmt_filter(wbuf)) { /* * filtered out and freed by the filter function, * nothing to do, just return. */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, "[%s] frame filtered out; do not send\n", __func__); ieee80211node_test_set_delayed_node_cleanup_fail(ni, IEEE80211_NODE_DELAYED_CLEANUP_FAIL); ieee80211_free_node(ni, WLAN_MGMT_TX_ID); return EOK; } } vap->iv_lastdata = OS_GET_TIMESTAMP(); #if 0 if (wbuf_is_keepalive(wbuf)){ if (force_send) qdf_nofl_info("\n the force_send is set\n"); if(ieee80211node_has_flag(ni,IEEE80211_NODE_PWR_MGT)){ qdf_nofl_info("\n powersave node\n"); for (int i = 0; i < 6; i++) { qdf_nofl_info("%02x:", ni->ni_macaddr[i]); } } } #endif /* * do not sent the frame is node is in power save (or) if the vap is paused * and the frame is is not marked as special force_send frame, and if the node * is temporary, don't do pwrsave */ if (!force_send && (ieee80211node_is_paused(ni)) && !ieee80211node_has_flag(ni, IEEE80211_NODE_TEMP)) { #if !LMAC_SUPPORT_POWERSAVE_QUEUE wlan_wbuf_set_peer_node(wbuf, NULL); #endif ieee80211node_pause(ni); /* pause it to make sure that no one else unpaused it after the node_is_paused check above, pause operation is ref counted */ ieee80211_node_saveq_queue(ni,wbuf,IEEE80211_FC0_TYPE_MGT); ieee80211node_unpause(ni); /* unpause it if we are the last one, the frame will be flushed out */ #if !LMAC_SUPPORT_POWERSAVE_QUEUE ieee80211node_test_set_delayed_node_cleanup_fail(ni, IEEE80211_NODE_DELAYED_CLEANUP_FAIL); ieee80211_free_node(ni, WLAN_MGMT_TX_ID); return EOK; #endif } /* * if the vap is not ready drop the frame. */ if (!(vap->iv_opmode == IEEE80211_M_HOSTAP && vap->iv_is_up) && (wlan_vdev_chan_config_valid(vap->vdev_obj) != QDF_STATUS_SUCCESS) && !vap->iv_special_vap_mode && !vap->iv_dpp_vap_mode) { struct ieee80211_tx_status ts; ts.ts_flags = IEEE80211_TX_ERROR; ts.ts_retries=0; /* * complete buf will decrement the pending count. */ ieee80211_complete_wbuf(wbuf,&ts); return EOK; } #ifdef QCA_SUPPORT_CP_STATS peer_cp_stats_tx_mgmt_inc(ni->peer_obj, 1); vdev_ucast_cp_stats_tx_mgmt_inc(vap->vdev_obj, 1); #endif if ((wh->i_fc[0] == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ASSOC_RESP)) || (wh->i_fc[0] == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_REASSOC_RESP))) { wbuf_set_complete_handler(wbuf, ieee80211_mlme_frame_complete_handler, ni); } // 实际发送过程 /* Hand over the wbuf to the mgmt_txrx infrastructure. */ retval = wlan_mgmt_txrx_mgmt_frame_tx(ni->peer_obj, NULL, wbuf, NULL, ieee80211_mgmt_complete_wbuf, WLAN_UMAC_COMP_MLME, NULL); if(QDF_IS_STATUS_ERROR(retval)) { struct ieee80211_tx_status ts; ts.ts_flags = IEEE80211_TX_ERROR; ts.ts_retries=0; #ifdef QCA_SUPPORT_CP_STATS vdev_cp_stats_tx_not_ok_inc(vap->vdev_obj, 1); #endif if ((fc_type == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ASSOC_RESP)) || (fc_type == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_REASSOC_RESP))) { #ifdef QCA_SUPPORT_CP_STATS WLAN_PEER_CP_STAT(ni, tx_assoc_fail); #endif } #ifdef QCA_SUPPORT_CP_STATS peer_cp_stats_tx_mgmt_dec(ni->peer_obj, 1); #endif ieee80211_complete_wbuf(wbuf,&ts); } else if ((fc_type == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ASSOC_RESP)) || (fc_type == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_REASSOC_RESP))) { if (ni->ni_assocstatus == IEEE80211_STATUS_SUCCESS) { #ifdef QCA_SUPPORT_CP_STATS WLAN_PEER_CP_STAT(ni, tx_assoc); #endif } else { #ifdef QCA_SUPPORT_CP_STATS WLAN_PEER_CP_STAT(ni, tx_assoc_fail); #endif } } return -retval; } ``` 在往下就是下面的过程了 ``` ieee80211_send_mgmt wlan_mgmt_txrx_mgmt_frame_tx{ tx_ops->mgmt_txrx_tx_ops.mgmt_tx_send(vdev, buf, desc->desc_id, mgmt_tx_params) 实际调用 ol_if_mgmt_send 因为 tx_ops->mgmt_txrx_tx_ops.mgmt_tx_send = ol_if_mgmt_send { ol_ath_tx_mgmt_wmi_send(ic, nbuf, ni, mgmt_tx_params); ol_mgmt_send wmi_mgmt_unified_cmd_send wmi_handle->ops->send_mgmt_cmd 实际调用 send_mgmt_cmd_tlv,因为 wmi_handle->ops->send_mgmt_cmd = send_mgmt_cmd_tlv { wmi_unified_cmd_send wmi_htc_send_pkt htc_send_pkt __htc_send_pkt } } } ``` ## 高阶 ### 去掉roam时probe 请求帧 ``` void ieee80211_mlme_join_infra_continue(struct ieee80211vap *vap, int32_t status) { if ((ic->ic_strict_pscan_enable && IEEE80211_IS_CHAN_PASSIVE(ic->ic_curchan)) && !vap->iv_wps_mode) { mlme_priv->im_request_type = MLME_REQ_NONE; IEEE80211_DELIVER_EVENT_MLME_JOIN_COMPLETE_INFRA(vap, IEEE80211_STATUS_SUCCESS); return; } else { /* Send a direct probe to increase the odds of receiving a probe response */ // 把下面的屏蔽掉,并且wpa_cli 需要把list_network bssid 字段为 any,可以用 // wpa_cli -p /var/run/wpa_supplicant-ath0 -iath0 set_network 0 bssid "any" 命令设置,然后进行roam // ieee80211_send_probereq(ni, vap->iv_myaddr, ni->ni_bssid, // ni->ni_bssid, ni->ni_essid, ni->ni_esslen, // vap->iv_opt_ie.ie, vap->iv_opt_ie.length); WIM_LOG_DEBUG("SMAC:%s DMAC:%s",ether_sprintf(vap->iv_myaddr),ether_sprintf(ni->ni_bssid)); } } ```